//////////////////////////////////////////ok
#include"stdafx.h"
#include "bochs.h"




void IA32_CPU::POP_Ed(Ia32_Instruction_c *i)
{
  Bit32u val32;
  pop_32(&val32);

  if (i->modC0()) 
  {
    IA32_WRITE_32BIT_REGZ(i->rm(), val32);
  }
  else 
  {
    if (i->as32L() && (!i->modC0()) && (i->rm()==4) && (i->sibBase()==4)) 
	{
      IA32_CPU_CALL_METHODR (i->ResolveModrm, (i));
    }
    write_virtual_dword(i->seg(), IA32_RMAddr(i), &val32);
  }
}

void IA32_CPU::PUSH_ERX(Ia32_Instruction_c *i)
{
  push_32( gen_reg[i->opcodeReg()].dword.erx);
}

void IA32_CPU::POP_ERX(Ia32_Instruction_c *i)
{
  Bit32u erx;
  pop_32(&erx);
   gen_reg[i->opcodeReg()].dword.erx = erx;
}

void IA32_CPU::PUSH_CS(Ia32_Instruction_c *i)
{
  if (i->os32L()) 
  {
    Bit32u eSP;
    decrementESPForPush(4, &eSP);
    write_virtual_word(IA32_SEG_REG_SS, eSP,& sregs[IA32_SEG_REG_CS].selector.value);
  }
  else
    push_16( sregs[IA32_SEG_REG_CS].selector.value);
}

void IA32_CPU::PUSH_DS(Ia32_Instruction_c *i)
{
  if (i->os32L()) 
  {
    Bit32u eSP;
    decrementESPForPush(4, &eSP);
    write_virtual_word(IA32_SEG_REG_SS, eSP, & sregs[IA32_SEG_REG_DS].selector.value);
  }
  else
    push_16( sregs[IA32_SEG_REG_DS].selector.value);
}

void IA32_CPU::PUSH_ES(Ia32_Instruction_c *i)
{
  if (i->os32L()) 
  {
    Bit32u eSP;
    decrementESPForPush(4, &eSP);
    write_virtual_word(IA32_SEG_REG_SS, eSP, & sregs[IA32_SEG_REG_ES].selector.value);
  }
  else
    push_16( sregs[IA32_SEG_REG_ES].selector.value);
}

void IA32_CPU::PUSH_FS(Ia32_Instruction_c *i)
{
  if (i->os32L()) 
  {
    Bit32u eSP;
    decrementESPForPush(4, &eSP);
    write_virtual_word(IA32_SEG_REG_SS, eSP, & sregs[IA32_SEG_REG_FS].selector.value);
  }
  else
    push_16( sregs[IA32_SEG_REG_FS].selector.value);
}

void IA32_CPU::PUSH_GS(Ia32_Instruction_c *i)
{
  if (i->os32L()) 
  {
    Bit32u eSP;
    decrementESPForPush(4, &eSP);
    write_virtual_word(IA32_SEG_REG_SS, eSP, & sregs[IA32_SEG_REG_GS].selector.value);
  }
  else
    push_16( sregs[IA32_SEG_REG_GS].selector.value);
}

void IA32_CPU::PUSH_SS(Ia32_Instruction_c *i)
{
  if (i->os32L()) 
  {
    Bit32u eSP;
    decrementESPForPush(4, &eSP);
    write_virtual_word(IA32_SEG_REG_SS, eSP, & sregs[IA32_SEG_REG_SS].selector.value);
  }
  else
    push_16( sregs[IA32_SEG_REG_SS].selector.value);
}

void IA32_CPU::POP_DS(Ia32_Instruction_c *i)
{
  if (i->os32L()) 
  {
    Bit32u ds;
    pop_32(&ds);
    load_seg_reg(& sregs[IA32_SEG_REG_DS], (Bit16u) ds);
  }
  else 
  {
    Bit16u ds;
    pop_16(&ds);
    load_seg_reg(& sregs[IA32_SEG_REG_DS], ds);
  }
}

void IA32_CPU::POP_ES(Ia32_Instruction_c *i)
{
  if (i->os32L()) 
  {
    Bit32u es;
    pop_32(&es);
    load_seg_reg(& sregs[IA32_SEG_REG_ES], (Bit16u) es);
  }
  else 
  {
    Bit16u es;
    pop_16(&es);
    load_seg_reg(& sregs[IA32_SEG_REG_ES], es);
  }
}

void IA32_CPU::POP_FS(Ia32_Instruction_c *i)
{
  if (i->os32L()) 
  {
    Bit32u fs;
    pop_32(&fs);
    load_seg_reg(& sregs[IA32_SEG_REG_FS], (Bit16u) fs);
  }
  else 
  {
    Bit16u fs;
    pop_16(&fs);
    load_seg_reg(& sregs[IA32_SEG_REG_FS], fs);
  }

}

void IA32_CPU::POP_GS(Ia32_Instruction_c *i)
{
  if (i->os32L()) 
  {
    Bit32u gs;
    pop_32(&gs);
    load_seg_reg(& sregs[IA32_SEG_REG_GS], (Bit16u) gs);
  }
  else 
  {
    Bit16u gs;
    pop_16(&gs);
    load_seg_reg(& sregs[IA32_SEG_REG_GS], gs);
  }
}

void IA32_CPU::POP_SS(Ia32_Instruction_c *i)
{
  if (i->os32L()) 
  {
    Bit32u ss;
    pop_32(&ss);
    load_seg_reg(& sregs[IA32_SEG_REG_SS], (Bit16u) ss);
  }
  else 
  {
    Bit16u ss;
    pop_16(&ss);
    load_seg_reg(& sregs[IA32_SEG_REG_SS], ss);
  }

   inhibit_mask |= IA32_INHIBIT_INTERRUPTS | IA32_INHIBIT_DEBUG;
   async_event = 1;
}

void IA32_CPU::PUSHAD32(Ia32_Instruction_c *i)
{

	Bit32u temp_ESP;
	Bit32u esp;

	if ( sregs[IA32_SEG_REG_SS].cache.u.segment.d_b)
		temp_ESP = ESP;
	else
		temp_ESP = SP;

    if (! can_push(& sregs[IA32_SEG_REG_SS].cache, temp_ESP, 32)) 
	{
        exception(IA32_SS_EXCEPTION, 0, 0);
        return;
    }

	esp = ESP;
	push_32(EAX);
	push_32(ECX);
	push_32(EDX);
	push_32(EBX);
	push_32(esp);
	push_32(EBP);
	push_32(ESI);
	push_32(EDI);

}

void IA32_CPU::POPAD32(Ia32_Instruction_c *i)
{
	Bit32u edi, esi, ebp, etmp, ebx, edx, ecx, eax;

	if ( !can_pop(32) ) 
	{
		exception(IA32_SS_EXCEPTION, 0, 0);
		return;
	}

	pop_32(&edi);
	pop_32(&esi);
	pop_32(&ebp);
	pop_32(&etmp); /* value for ESP discarded */
	pop_32(&ebx);
	pop_32(&edx);
	pop_32(&ecx);
	pop_32(&eax);

	EDI = edi;
	ESI = esi;
	EBP = ebp;
	EBX = ebx;
	EDX = edx;
	ECX = ecx;
	EAX = eax;
}

void IA32_CPU::PUSH_Id(Ia32_Instruction_c *i)
{
  push_32(i->Id());
}

void IA32_CPU::PUSH_Ed(Ia32_Instruction_c *i)
{
	Bit32u op1_32;

	if (i->modC0()) 
	{
		op1_32 = IA32_READ_32BIT_REG(i->rm());
	}
	else 
	{
		read_virtual_dword(i->seg(), IA32_RMAddr(i), &op1_32);
	}
	push_32(op1_32);

}

void IA32_CPU::ENTER_IwIb(Ia32_Instruction_c *i)
{

  unsigned ss32 =  sregs[IA32_SEG_REG_SS].cache.u.segment.d_b;
  Bit16u imm16 = i->Iw();
  Bit8u level = i->Ib2();
  level &= 0x1F;

  Bit32u ebp; // Use temp copy in case of exception.

  if (i->os32L())
    push_32(EBP);
  else
    push_16(BP);

  Bit32u frame_ptr32 = ESP;

  if (ss32) 
  {
    ebp = EBP;
  }
  else 
  {
    ebp = BP;
  }

  if (level > 0) 
  {
    while (--level) 
	{
		if (i->os32L()) 
		{
				Bit32u temp32;
				if (ss32) 
				{
					ebp -= 4;
					read_virtual_dword(IA32_SEG_REG_SS, ebp, &temp32);
				}
				else 
				{ /* 16bit stacksize */
					ebp -= 4; ebp &= 0xffff;
					read_virtual_dword(IA32_SEG_REG_SS, ebp, &temp32);
				}
				push_32(temp32);
		}
		else 
		{ /* 16bit opsize */
			Bit16u temp16;
			if (ss32) 
			{
				ebp -= 2;
				read_virtual_word(IA32_SEG_REG_SS, ebp, &temp16);
			}
			else 
			{ /* 16bit stacksize */
				ebp -= 2; ebp &= 0xffff;
				read_virtual_word(IA32_SEG_REG_SS, ebp, &temp16);
			}
			push_16(temp16);
		}
      } /* while (--level) */

    if (i->os32L()) 
	{
      push_32(frame_ptr32);
    }
    else 
	{ 
      push_16((Bit16u)frame_ptr32);
    }
  } /* if (level > 0) ... */

  if (ss32) 
  {
    EBP = frame_ptr32;
    ESP -= imm16;
  }
  else 
  {
    BP = (Bit16u) frame_ptr32;
    SP -= imm16;
  }

}

void IA32_CPU::LEAVE(Ia32_Instruction_c *i)
{
	Bit32u temp_EBP;

	if ( sregs[IA32_SEG_REG_SS].cache.u.segment.d_b)
		temp_EBP = EBP;
	else
		temp_EBP = BP;

    if ( sregs[IA32_SEG_REG_SS].cache.u.segment.c_ed) 
	{ 
		if (temp_EBP <=  sregs[IA32_SEG_REG_SS].cache.u.segment.limit_scaled) 
		{
			exception(IA32_SS_EXCEPTION, 0, 0);
		}
    }
    else 
	{ 
		if (temp_EBP >  sregs[IA32_SEG_REG_SS].cache.u.segment.limit_scaled) 
		{
			exception(IA32_SS_EXCEPTION, 0, 0);
		}
    }


	if ( sregs[IA32_SEG_REG_SS].cache.u.segment.d_b)
		ESP = EBP;
	else
		SP = BP;

	if (i->os32L()) 
	{
		Bit32u temp32;
		pop_32(&temp32);
		EBP = temp32;
	}
	else
	{
		Bit16u temp16;
		pop_16(&temp16);
		BP = temp16;
	}

}
